package com.kcht.itsed.mws.devicescheduler.biz;

import com.kcht.itsed.mws.devicescheduler.ReaderRegisterEvent;
import com.kcht.itsed.mws.devicescheduler.facade.IPhysicalReaderDriverRegister;
import com.kcht.itsed.mws.devicescheduler.facade.IPhysicalReaderLinkManager;
import com.kcht.itsed.mws.extendalemodel.PRSpec;
import com.kcht.itsed.mws.persist.dao.IPhysicalReaderDao;
import com.shhic.itsed.mws.deviceintf.IDeviceIntf;
import com.shhic.itsed.mws.deviceintf.ReaderLinkStatusEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

@Component
@Slf4j
public class PhysicalReaderLinkManager implements IPhysicalReaderLinkManager,IPhysicalReaderDriverRegister {

	enum PhysicalReaderUse{
		IDLE,ACTIVE
	}
	
	class InnerPhysicalReader{
		PRSpec spec;
		PhysicalReaderUse useState = PhysicalReaderUse.IDLE;
	}
	
	@Autowired
	IPhysicalReaderDao prDao;

	@Autowired
	private ApplicationContext applicationContext;
	
	private Map<String,InnerPhysicalReader> readerContainer = new HashMap<>();//阅读器容器，注意：key是IP地址
	private Map<String,IDeviceIntf> readerDriverMap = new HashMap<>();	//阅读器驱动容器，key是阅读器类型

	@PostConstruct
	public void loadAllExistedPhysicalReader() {
		applicationContext.publishEvent(new ReaderRegisterEvent(this));
		prDao.getAllPRs().forEach(e->{
			InnerPhysicalReader pr = new InnerPhysicalReader();
			pr.spec = e.getPrSpec();
			readerContainer.put(e.getReaderIp(),pr);
		});
	}
	
	@Override
	public void refreshAllActiveReader(Set<String> allActiveReaderIp) {
		// 首先关闭所有不用的阅读器
		readerContainer.entrySet().forEach(entry->{
			String readerIp = entry.getKey();
			InnerPhysicalReader reader = entry.getValue();
			
			//需要停止的阅读器
			if(!allActiveReaderIp.contains(readerIp) && reader.useState == PhysicalReaderUse.ACTIVE) 
				stopReader(reader.spec);
			
			//需要打开的阅读器
			if(allActiveReaderIp.contains(readerIp) && reader.useState == PhysicalReaderUse.IDLE) 
				startReader(reader.spec);
		});
	}


	private void startReader(PRSpec readerSpec) {
		//启动阅读器
		String readerIp = readerSpec.getReaderIp();
		int port = readerSpec.getReaderPort();
		Map<String, String> initParams = new HashMap<>();
		
		if(readerSpec.getInitParams() != null) 
			readerSpec.getInitParams().getParam()
				.forEach(p -> initParams.put(p.getName(), p.getValue()));
		
		fetchDriver(readerSpec.getReaderClass()).ifPresent(p->{
			log.info("--------------- begin to init reader:" + readerIp + "----------------");
			if(initParams.isEmpty())p.initReader(readerIp, port);
			else p.initReader(readerIp, port, initParams);
			log.info("--------------- finish init reader:" + readerIp + "----------------");

			readerContainer.get(readerIp).useState = PhysicalReaderUse.ACTIVE;
		});
	}

	private void stopReader(PRSpec readerSpec) {
		//停止有阅读器
		String readerIp = readerSpec.getReaderIp();
		fetchDriver(readerSpec.getReaderClass()).ifPresent(p->{
			log.info("--------------- begin to stop reader:" + readerIp + "----------------");
			p.stopReaderCommand(readerIp);
			log.info("--------------- finish stop reader:" + readerIp + "----------------");
//			p.disconnectReader(readerIp);
			readerContainer.get(readerIp).useState = PhysicalReaderUse.IDLE;
		});
	}

	@Override
	public void addPhysicalReader(PRSpec pr) {
		if(readerContainer.containsKey(pr.getReaderIp())) {
			readerContainer.get(pr.getReaderIp()).spec = pr;
		}else {
			readerContainer.put(pr.getReaderIp(), new InnerPhysicalReader() {{ spec = pr; }});
		}
	}


	@Override
	public boolean isPhysicalReaderInUse(String readerIp) {
		return readerContainer.containsKey(readerIp) && readerContainer.get(readerIp).useState == PhysicalReaderUse.ACTIVE;
	}

	@Override
	public void removePhysicalReader(String readerIp) {
		readerContainer.remove(readerIp);
	}

	@Override
	public void registerPhysicalReaderDriver(String readerType,IDeviceIntf driver) {
		readerDriverMap.put(readerType, driver);
	}

	@Override
	public Optional<IDeviceIntf> fetchDriver(String readerType) {
		return Optional.ofNullable(readerDriverMap.get(readerType));
	}

	@Override
	public String getReaderLinkState(String readerIp) {
		InnerPhysicalReader innerPhysicalReader = readerContainer.get(readerIp);
		if(innerPhysicalReader != null) {
			IDeviceIntf devIntf = readerDriverMap.get(innerPhysicalReader.spec.getReaderClass());
			if(devIntf != null) {
				ReaderLinkStatusEnum linkStatus = devIntf.queryDeviceLinkstatus(readerIp);
				if(linkStatus == null)return "UNUSED";
				return linkStatus.name();
			}
		}
		return "UNKNOWN";
	}
	
}
